// Copyright (c) 2007 Alistair Jones
// This program is made available under the terms of the MIT License.
package org.hypirinha.html.codegen;

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.Map;
import java.util.HashMap;

public class AttributeGenerator {

    public List<CompilationUnit> generate() {

        Document schema = new SchemaParser().parseSchema();

        Map<String, Attribute> attributes = new HashMap<String, Attribute>();

        XPath xPath = XPathUtil.createXPath();
        try {
            NodeList nodes = (NodeList) xPath.evaluate("/xs:schema/xs:element", schema, XPathConstants.NODESET);

            for (int i = 0; i < nodes.getLength(); i++) {
                String elementName = xPath.evaluate("@name", nodes.item(i));
                Set<String> attributeNames = new AttributeFinder(schema).findAttributes(elementName);
                for (String attributeName : attributeNames) {
                    Attribute attribute = findOrCreateAttribute(attributes, attributeName);
                    attribute.addApplicableElement(elementName);
                }
            }

        } catch (XPathExpressionException e) {
            throw new RuntimeException(e);
        }

        addUnofficialAttributes(attributes);

        ArrayList<CompilationUnit> classes = new ArrayList<CompilationUnit>();
        for (Attribute attribute : attributes.values()) {
            classes.add(attribute.createAttributeImplementation());
        }
        classes.add(new AttributeFactory(attributes.keySet()).createImplementation());
        return classes;
    }

    private void addUnofficialAttributes(Map<String, Attribute> attributes) {
        Attribute autoCompleteAttribute = findOrCreateAttribute(attributes, "autocomplete");
        autoCompleteAttribute.addApplicableElement("input");
    }

    private Attribute findOrCreateAttribute(Map<String, Attribute> attributes, String attributeName) {
        if (attributes.containsKey(attributeName)) {
            return attributes.get(attributeName);
        }
        Attribute attribute = new Attribute(attributeName);
        attributes.put(attributeName, attribute);
        return attribute;
    }

}